#include <GL/glut.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "lc_array.h"
#include "pac_level.h"
#include "pac_object.h"
#include "pac_drawer3D.h"
#include "pac_logger.h"
#include "pac_values.h"
#include "pac_ghost.h"
#include "pac_tools.h"
#include "pac_game.h"

// Valeur de déacalage de la bouche de pacman
float pacManMouthValue = 0.25;

// Booléen indiquant si la bouche grossi ou non
boolean pacManMouthIsGrowing = FALSE;

void load3DTextures(void) {
    pac_log(LOG_DEBUG, "load3DTextures\n");

    // Données des textures
    GLubyte* texData;

   // Tailles des textures
    int texWidth, texHeight;
    
    // Création du tableau de textures
    glGenTextures(TEX_3D_COUNT, tex3DTable);
    
    // Assignation de valeur de répétition des textures
    texRepeatCount[WALL_TEX] = 5.0;
    texRepeatCount[FLOOR_TEX] = 4.0;
    texRepeatCount[FRIZE_TEX] = 10.0;
    texRepeatCount[VORTEX_TEX] = 1.0;
    texRepeatCount[FENCE_TEX] = 1.0;
        texRepeatCount[SPACE_TEX] = 50.0;

    // Chargement de la texture de mur
    texData = glmReadPPM("Textures/brick.ppm", &texWidth, &texHeight);
    glBindTexture(GL_TEXTURE_2D, tex3DTable[WALL_TEX]);
    initPacTexture(texData, texWidth, texHeight);

    // Chargement de la texture de sol
    texData = glmReadPPM("Textures/floor.ppm", &texWidth, &texHeight);
    glBindTexture(GL_TEXTURE_2D, tex3DTable[FLOOR_TEX]);
    initPacTexture(texData, texWidth, texHeight);

    // Chargement de la texture de frise
    texData = glmReadPPM("Textures/frise.ppm", &texWidth, &texHeight);
    glBindTexture(GL_TEXTURE_2D, tex3DTable[FRIZE_TEX]);
    initPacTexture(texData, texWidth, texHeight);

    // Chargement de la texture de vortex
    texData = glmReadPPM("Textures/vortex.ppm", &texWidth, &texHeight);
    glBindTexture(GL_TEXTURE_2D, tex3DTable[VORTEX_TEX]);
    initPacTexture(texData, texWidth, texHeight);

    // Chargement de la texture de barrière
    texData = glmReadPPM("Textures/fence.ppm", &texWidth, &texHeight);
    glBindTexture(GL_TEXTURE_2D, tex3DTable[FENCE_TEX]);
    initPacTexture(texData, texWidth, texHeight);
    
        // Chargement de la texture de l'espace
    texData = glmReadPPM("Textures/space.ppm", &texWidth, &texHeight);
    glBindTexture(GL_TEXTURE_2D, tex3DTable[SPACE_TEX]);
    initPacTexture(texData, texWidth, texHeight);
    
    printf("DONE\n");
}


void drawSideFriz(int x, int y) {

    glPushMatrix();
    glTranslatef(x, 0, y);

    glBindTexture(GL_TEXTURE_2D, tex3DTable[FRIZE_TEX]);

    glBegin(GL_QUADS);
    glTexCoord2f(0.0, 0.0);
    glVertex3f(0.0001, 0.9, 0.0);
    glTexCoord2f(0.0, texRepeatCount[FRIZE_TEX]);
    glVertex3f(0.0001, 0.9, 1.0);
    glTexCoord2f(1.0, texRepeatCount[FRIZE_TEX]);
    glVertex3f(0.0001, 1.0, 1.0);
    glTexCoord2f(1.0,  0);
    glVertex3f(0.0001, 1.0, 0.0);
    glEnd();

    glBegin(GL_QUADS);
    glTexCoord2f(0.0, 0.0);
    glVertex3f(-0.0001, 0.9, 0.0);
    glTexCoord2f(0.0,  texRepeatCount[FRIZE_TEX]);
    glVertex3f(-0.0001, 0.9, 1.0);
    glTexCoord2f(1.0,  texRepeatCount[FRIZE_TEX]);
    glVertex3f(-0.0001, 1.0, 1.0);
    glTexCoord2f(1.0, 0.0);
    glVertex3f(-0.0001, 1.0, 0.0);
    glEnd();

    glPopMatrix();
}

void drawFaceFriz(int x, int y) {

    glPushMatrix();
    glTranslatef(x, 0, y);

    glBindTexture(GL_TEXTURE_2D, tex3DTable[FRIZE_TEX]);
    glBegin(GL_QUADS);
    glTexCoord2f(0.0, 0.0);
    glVertex3f(0, 0.9, 0.0001);
    glTexCoord2f(0.0, texRepeatCount[FRIZE_TEX]);
    glVertex3f(1, 0.9, 0.0001);
    glTexCoord2f(1.0, texRepeatCount[FRIZE_TEX]);
    glVertex3f(1, 1.0, 0.0001);
    glTexCoord2f(1.0, 0.0);
    glVertex3f(0, 1.0, 0.0001);
    glEnd();

    glBegin(GL_QUADS);
    glTexCoord2f(0.0, 0.0);
    glVertex3f(0, 0.9, -0.0001);
    glTexCoord2f(0.0, texRepeatCount[FRIZE_TEX]);
    glVertex3f(1, 0.9, -0.0001);
    glTexCoord2f(1.0, texRepeatCount[FRIZE_TEX]);
    glVertex3f(1, 1.0, -0.0001);
    glTexCoord2f(1.0, 0.0);
    glVertex3f(0, 1.0, -0.0001);
    glEnd();

    glPopMatrix();
}

void drawSideWall(int x, int y, int aTexIndex) {

    glPushMatrix();
    glTranslatef(x, 0, y);
    glBindTexture(GL_TEXTURE_2D, tex3DTable[aTexIndex]);

    glBegin(GL_QUADS);
    
    glTexCoord2f(texRepeatCount[aTexIndex], 0.0);
    glVertex3f(0.0, 0.0, 0.0);

    glTexCoord2f(0.0, 0.0);
    glVertex3f(0.0, 0.0, 1.0);

    glTexCoord2f(0.0, texRepeatCount[aTexIndex]);
    glVertex3f(0.0, 1.0, 1.0);

    glTexCoord2f(texRepeatCount[aTexIndex], texRepeatCount[aTexIndex]);
    glVertex3f(0.0, 1.0, 0.0);

    glEnd();

    glPopMatrix();
    
}

void drawFaceWall(int x, int y, int aTexIndex) {

    glPushMatrix();
    glTranslatef(x, 0, y);
    glBindTexture(GL_TEXTURE_2D, tex3DTable[aTexIndex]);

    glBegin(GL_QUADS);
    
    glTexCoord2f(0.0, texRepeatCount[aTexIndex]);
    glVertex3f(0.0, 0.0, 0.0);

    glTexCoord2f(texRepeatCount[aTexIndex], texRepeatCount[aTexIndex]);
    glVertex3f(1.0, 0.0, 0.0);

    glTexCoord2f(texRepeatCount[aTexIndex], 0.0);
    glVertex3f(1.0, 1.0, 0.0);

    glTexCoord2f(0.0, 0.0);
    glVertex3f(0.0, 1.0, 0.0);
    
    glEnd();

    glPopMatrix();
}

void drawFrontWall(int x, int y, int aTexIndex) {
    drawFaceWall(x, y,aTexIndex);
}

void drawLeftWall(int x, int y, int aTexIndex) {
    drawSideWall(x, y,aTexIndex);
}

void drawRightWall(int x, int y, int aTexIndex) {
    drawSideWall(x + 1, y,aTexIndex);
}

void drawBackWall(int x, int y, int aTexIndex) {
    drawFrontWall(x, y + 1,aTexIndex);
}

void drawFloor(int x, int y, int aTexIndex) {

    glPushMatrix();
    glTranslatef(x, 0, y);

    glBindTexture(GL_TEXTURE_2D, tex3DTable[aTexIndex]);

    glBegin(GL_QUADS);

    glTexCoord2f(0.0, 0.0);
    glVertex3f(0.0, 0.0, 0.0);
    glTexCoord2f(0.0, texRepeatCount[aTexIndex]);
    glVertex3f(1.0, 0.0, 0.0);
    glTexCoord2f(texRepeatCount[aTexIndex], texRepeatCount[aTexIndex]);
    glVertex3f(1.0, 0.0, 1.0);
    glTexCoord2f(texRepeatCount[aTexIndex], 0.0);
    glVertex3f(0.0, 0.0, 1.0);
    glEnd();

    glPopMatrix();
}

void drawRoof(int x, int y, int aTexIndex) {

    glPushMatrix();
    glTranslatef(x, 0, y);
    glBindTexture(GL_TEXTURE_2D, tex3DTable[aTexIndex]);

    glBegin(GL_QUADS);
    glTexCoord2f(0.0, 0.0);
    glVertex3f(0.0, 1.0, 0.0);
    glTexCoord2f(0.0, texRepeatCount[aTexIndex]);
    glVertex3f(1.0, 1.0, 0.0);
    glTexCoord2f(texRepeatCount[aTexIndex], texRepeatCount[aTexIndex]);
    glVertex3f(1.0, 1.0, 1.0);
    glTexCoord2f(texRepeatCount[aTexIndex], 0.0);
    glVertex3f(0.0, 1.0, 1.0);
    glEnd();

    glPopMatrix();
}

void drawBlock(int x, int y, int aTexIndex) {

    drawLeftWall(x, y, aTexIndex);
    drawRightWall(x, y, aTexIndex);
    drawFrontWall(x, y, aTexIndex);
    drawBackWall(x, y, aTexIndex);
    drawRoof(x, y, WALL_TEX);
}

void drawBlockWithFrize(int x, int y, int aTexIndex) {

    drawLeftWall(x, y, aTexIndex);
    drawSideFriz(x, y);

    drawRightWall(x, y, aTexIndex);
    drawSideFriz(x + 1, y);

    drawFrontWall(x, y, aTexIndex);
    drawFaceFriz(x, y);

    drawBackWall(x, y, aTexIndex);
    drawFaceFriz(x, y + 1);

    drawRoof(x, y, aTexIndex);
}

void drawSkyBox(){
    glPushMatrix();

    glBindTexture(GL_TEXTURE_2D, tex3DTable[SPACE_TEX]);

    // Texture du sol
    glBegin(GL_QUADS);
    glTexCoord2f(0, 0);
    glVertex3f(50, -10, 100);

    glTexCoord2f(0, texRepeatCount[SPACE_TEX]);
    glVertex3f(-100, -10, 100);

    glTexCoord2f(texRepeatCount[SPACE_TEX], texRepeatCount[SPACE_TEX]);
    glVertex3f(-100, -10, -50);

    glTexCoord2f(texRepeatCount[SPACE_TEX], 0);
    glVertex3f(50, -10, -50);
    glEnd();

    // Texture gauche
    glBegin(GL_QUADS);
    glTexCoord2f(0, 0);
    glVertex3f(50, 20, -50);

    glTexCoord2f(0, texRepeatCount[SPACE_TEX]);
    glVertex3f(50, 20, 100);

    glTexCoord2f(texRepeatCount[SPACE_TEX], texRepeatCount[SPACE_TEX]);
    glVertex3f(50, -10, 100);

    glTexCoord2f(texRepeatCount[SPACE_TEX], 0);
    glVertex3f(50, -10, -50);
    glEnd();


    // Texture droite
    glBegin(GL_QUADS);
    glTexCoord2f(0, 0);
    glVertex3f(-100, 20, 100);

    glTexCoord2f(0, texRepeatCount[SPACE_TEX]);
    glVertex3f(-100, 20, -50);

    glTexCoord2f(texRepeatCount[SPACE_TEX], texRepeatCount[SPACE_TEX]);
    glVertex3f(-100, -10, -50);

    glTexCoord2f(texRepeatCount[SPACE_TEX], 0);
    glVertex3f(-100, -10, 100);
    glEnd();



    // Texture devant
    glBegin(GL_QUADS);
    glTexCoord2f(0, 0);
    glVertex3f(50, 20, 100);

    glTexCoord2f(0, texRepeatCount[SPACE_TEX]);
    glVertex3f(-100, 20, 100);

    glTexCoord2f(texRepeatCount[SPACE_TEX], texRepeatCount[SPACE_TEX]);
    glVertex3f(-100, -10, 100);

    glTexCoord2f(texRepeatCount[SPACE_TEX], 0);
    glVertex3f(50, -10, 100);
    glEnd();


    // Texture derriere
    glBegin(GL_QUADS);
    glTexCoord2f(0, 0);
    glVertex3f(-100, 20, -50);

    glTexCoord2f(0, texRepeatCount[SPACE_TEX]);
    glVertex3f(50, 20, -50);

    glTexCoord2f(texRepeatCount[SPACE_TEX], texRepeatCount[SPACE_TEX]);
    glVertex3f(50, -10, -50);

    glTexCoord2f(texRepeatCount[SPACE_TEX], 0);
    glVertex3f(-100, -10, -50);
    glEnd();

    glPopMatrix();
}

void draw3DSphere(float size, float posX, float posY, float posZ) {
    glPushMatrix();
    
    glBindTexture(GL_TEXTURE_2D, 0);
    glTranslatef(posX, posY, posZ);
    glutSolidSphere(size, 20, 20);
    
    glPopMatrix();
}

void drawGhostEyes(){
    
    glColor3f(1.0, 1.0, 1.0);
    glPushMatrix();
    glTranslatef(0.15, 0.1, 0.20);
    glutSolidSphere(0.08, 10, 10);
    glPopMatrix();

    glPushMatrix();
    glTranslatef(-0.15, 0.1, 0.20);
    glutSolidSphere(0.08, 10, 10);
    glPopMatrix();

    glColor3f(0.0, 0.0, 0.0);
    glPushMatrix();
    glTranslatef(0.17, 0.1, 0.26);
    glutSolidSphere(0.03, 10, 10);
    glPopMatrix();

    glPushMatrix();
    glTranslatef(-0.17, 0.1, 0.26);
    glutSolidSphere(0.03, 10, 10);
    glPopMatrix();
}

void drawGhostLegs(){
    
    glPushMatrix();
    glTranslatef(0, 0.02, 0);
    
        
    glPushMatrix();
    glRotatef(80, 1, 0 ,0 );
    glutSolidCone(0.30, 0.65, 10, 10);
    glRotatef(70, 1, 0 ,0 );
    glutSolidCone(0.30, 0.65, 10, 10);
    glPopMatrix();
    
    glPushMatrix();
    glRotatef(115, 1, 0 ,0 );
    
    glRotatef(-35, 0, 1 ,0 );
    glutSolidCone(0.30, 0.65, 10, 10);
    glRotatef(70, 0, 1 ,0 );
    glutSolidCone(0.30, 0.65, 10, 10);
    glPopMatrix();
    
   glPopMatrix();
}


void drawPacEyes(){
    glColor3f(0.0, 0.0, 0.0);
    glPushMatrix();
    glTranslatef(0.15, 0.2, 0.20);
    glutSolidSphere(0.35 / 3.5, 20, 20);
    glPopMatrix();

    glPushMatrix();
    glTranslatef(-0.15, 0.2, 0.20);
    glutSolidSphere(0.35 / 3.5, 20, 20);
    glPopMatrix();

    glColor3f(1.0, 1.0, 1.0);
    glPushMatrix();
    glTranslatef(0.17, 0.22, 0.27);
    glutSolidSphere(0.35 / 8.0, 20, 20);
    glPopMatrix();

    glPushMatrix();
    glTranslatef(-0.17, 0.22, 0.27);
    glutSolidSphere(0.35 / 8.0, 20, 20);
    glPopMatrix();
    
}

void drawPacMouth(void){
    glColor3f(0.3, 0.3, 0.3);
    glPushMatrix();
    glTranslatef(-0.10, -0.05,  pacManMouthValue );
    glutSolidSphere(0.35 / 3.5, 20, 20);
    glPopMatrix();

    glPushMatrix();
    glTranslatef(-0.05, -0.05,  pacManMouthValue +  0.015);
    glutSolidSphere(0.35 / 3.5, 20, 20);
    glPopMatrix();

    glPushMatrix();
    glTranslatef(0.0, -0.05, pacManMouthValue + 0.02);
    glutSolidSphere(0.35 / 3.5, 20, 20);
    glPopMatrix();

    glPushMatrix();
    glTranslatef(0.05, -0.05,  pacManMouthValue +  0.015 );
    glutSolidSphere(0.35 / 3.5, 20, 20);
    glPopMatrix();

    glPushMatrix();
    glTranslatef(0.10, -0.05,  pacManMouthValue);
    glutSolidSphere(0.35 / 3.5, 20, 20);
    glPopMatrix();

}

void draw3DPacManObject() {
    glPushMatrix();

    glBindTexture(GL_TEXTURE_2D, 0);

    // Dessin de la sphere de PacMan
    glColor3f(1.0, 1.0, 0.0);
    glutSolidSphere(0.35, 20, 20);

    // Dessin des yeux de PacMan
    drawPacEyes();
    
    // Dessin de la bouche de pacman
    drawPacMouth();
 
    // Dessin du nez de PacMan
    glColor3f(0.5, 0.5, 0.5);
    glTranslatef(0, 0.1, 0);
    glutSolidCone(0.2, 0.45, 10, 10);
    
    glPopMatrix();
}

void updatePacMouth(){
    
    glutTimerFunc(10, updatePacMouth, 1);
        
    if (pacManMouthIsGrowing){
           pacManMouthValue += 0.001;
    }
    else{
           pacManMouthValue -= 0.001;
    }
    
    if (pacManMouthValue >= 0.25){
        pacManMouthIsGrowing = FALSE;
    }
    
    if (pacManMouthValue <= 0.20){
        pacManMouthIsGrowing = TRUE;
    }
}

void executeRotationForObjectDirection(PacObject* aPacObject){
    // Récupération de la direction de l'objet
    int pacObjectDirection = aPacObject->currentMove;

    // Si l'objet ne bouge plus
    if (pacObjectDirection == NO_MOVE) {

        // Récupération du dernier déplacement
        pacObjectDirection = aPacObject->lastMove;
    }
    
    // Rotation  en fonction de la direction de l'objet
    switch (pacObjectDirection) {
            // Le déplacement courant est vers le haut
        case MOVE_UP:
            glRotatef(-25, 1, 0, 0);
            // Pas de déplacement
            break;

            // Le déplacement courant est vers le bas
        case MOVE_DOWN:
            // Rotation complete
            glRotatef(25, 1, 0, 0);
            glRotatef(180, 0, 1, 0);
            break;

            // Le déplacement courant est vers la gauche
        case MOVE_LEFT:
            // Demin rotation a gauche
            glRotatef(25, 0, 0, 1);
            glRotatef(90, 0, 1, 0);
            break;

            // Le déplacement courant est vers la droite
        case MOVE_RIGHT:
            // Demi rotation a doite
            glRotatef(-25, 0, 0, 1);
            glRotatef(-90, 0, 1, 0);
            break;

            // Dans les autres cas
        default:
            // La caméra ne doit pas changer
            break;
    }
}

void drawNormal3DPacManAt( PacObject* aPacMan, float posX, float posY, float posZ) {

    glPushMatrix();
          
    glBindTexture(GL_TEXTURE_2D, 0);
    
    // Déplacement à la position de pacman
    glTranslatef(posX, posY, posZ);

    // Rotation en fonction de la direction de PacMan
    executeRotationForObjectDirection(aPacMan);
    
    draw3DPacManObject();
              
    glPopMatrix();
}

void drawFPS3DPacManAt(float posX, float posY, float posZ) {
    glPushMatrix();
    glColor3f(1.0, 1.0, 0.0);
    glBindTexture(GL_TEXTURE_2D, 0);
    glTranslatef(posX, posY , posZ);
    glutSolidSphere(0.5, 20, 20);

    glPopMatrix();
}

void draw3DPacMan(PacGame * aPacGame, PacObject* aPacMan) {
    pac_log(LOG_DEBUG, "draw3DPacMan\n");

    // Si le jeu est en mode FPS
    if (aPacGame->isFPSMode) {
        // Dessin de pacman en temps que WireSphere
        drawFPS3DPacManAt(-aPacMan->posX+0.5, 0.7, aPacMan->posY+0.5);
    } else {
        // Dessin de pacman en temps que SolidSphere
        drawNormal3DPacManAt(aPacMan, -aPacMan->posX + 0.5, 0.5, aPacMan->posY + 0.5);
    }
}

void draw3DPacGum(int posX, int posY) {
    glColor3f(0, 0.5, 0.0);
    draw3DSphere(0.15, posX + 0.5, 0.5, posY + 0.5);
}

void draw3DPowerBall(int posX, int posY) {

    // Une chance sur 3 que la powerBall change de couleur
    if (getRandomIntUnder(3) == 1) {
        // La couleur est tirée aléatoirement
        float rValue = getRandomIntUnder(80) / 100.0;
        float gValue = getRandomIntUnder(80) / 100.0;
        float bValue = getRandomIntUnder(80) / 100.0;
        glColor3f(rValue, gValue, bValue);
    } else {
        // Couleur verte par défaut
        glColor3f(0.2, 0.8, 0.0);
    }
    // Dessin de la sphere
    draw3DSphere(0.25, posX + 0.5, 0.5, posY + 0.5);
}

void draw3DPacBall(PacLevel* aLevel, int aPacBallCode, int posX, int posY) {

    switch (aPacBallCode) {
        case PAC_GUM_CODE:
            draw3DPacGum(posX, posY);
            break;

        case POWER_BALL_CODE:
            draw3DPowerBall(posX, posY);
            break;

        default:
            // Do nothing...
            break;
    }
}

void update3DGhostColor(PacGame * aPacGame, PacGhost * aPacGhost){

    // Si le fantôme est vulnérable
    if (aPacGhost->isVulnerable) {
        // Il est bleu
        glColor3f(0.0, 0.0, 0.5);

        // Si le temps des pouvoir restant est inférieur à 2 seconde
        if (aPacGame->powerBallPowerTime <= 2000) {

            // Si le temps des pouvoir restant est inférieur à 1 seconde
            if (aPacGame->powerBallPowerTime <= 1000) {
                // Changement de la couleur de fantômes toutes les 100ms
                if (aPacGame->powerBallPowerTime % 200 >= 100) {
                    glColor3f(1, .5, 0);
                }
            }                
            else 
            // Entre 2 et 1 secondes
            {
                // Changement de la couleur de fantômes toutes les 250ms
                if (aPacGame->powerBallPowerTime % 500 >= 250) {
                    glColor3f(1, .5, 0);
                }
            }

        }
    }// Sinon, s'il retourne à la maison
    else if (aPacGhost->isGoingToHome) {
        // Il est blanc
        glColor3f(0.9, 0.9, 0.9);
    } else {
        // Sinon, Si le fantome est intelligent
        if (aPacGhost->isIntelligent) {
            // Il est en rouge foncé
            glColor3f(0.8, 0.0, 0.0);
        } else {
            // Sinon, il est rouge
            glColor3f(0.4, 0.1, 0.1);
        }
    }
}

void draw3DGhost(PacGame* aPacGame, PacGhost * aPacGhost) {

    glPushMatrix();

    // Mise à jour de la couleur du fantôme
    update3DGhostColor(aPacGame, aPacGhost);

    // Déplacement à la position du fantôme
    glTranslatef(-aPacGhost->pacObject->posX + 0.5, 0.65, aPacGhost->pacObject->posY + 0.5);

    // Dessin de la sphere du fantôme
    glutSolidSphere(0.3, 20, 20);

    // Rotation en fonction de la direction du fantôme
    executeRotationForObjectDirection(aPacGhost->pacObject);

    // Dessin des 'jambes' du fantôme
    drawGhostLegs();

    // Dessin des yeux du fantôme
    drawGhostEyes();


    glPopMatrix();
}

void draw3DGhosts(PacGame* aPacGame) {
    pac_log(LOG_DEBUG, "\n");
    // Récupération du nombre de fantômes
    int size = lcArrayLength(aPacGame->currentLevel->ghosts);

    PacGhost* currentGhost;
    int x;

    // Parcours de la liste des fantômes
    for (x = 0; x < size; x++) {

        // Récupération du fantôme courant
        currentGhost = lcArrayGet(aPacGame->currentLevel->ghosts, x);

        // Affichage du fantôme courant
        draw3DGhost(aPacGame, currentGhost);
    }
}

void draw3DCase(PacLevel* aLevel, int aCaseCode, int posX, int posY) {
    //printf("Drawing : '%d' at (%d,%d,%d)\n", aCaseCode, posX, posY);
    switch (aCaseCode) {
        case BLOCK_CODE:
            // Dessin d'un mur
            drawBlockWithFrize(posX, posY, WALL_TEX);
            break;

        case FENCE_CODE:
            // Dessin de la barrière
            drawBlock(posX, posY, FENCE_TEX);
            break;

        default:
            // Si le nombre est négatif
            if (aCaseCode < 0) {
                // Dessin du vortex
                drawBlock(posX, posY, VORTEX_TEX);
            } else {
                // Sinon, dessin du sol
                drawFloor(posX, posY, FLOOR_TEX);
            }
            break;
    }
}



void draw3DCases(PacLevel* aLevel) {
    pac_log(LOG_DEBUG, "draw3DCases\n");
    int x, y = 0;

    // Récupération de la taille de la map
    int sizeY = levelGetSizeY(aLevel);
    int sizeX = levelGetSizeX(aLevel);

    int currentCase;

    // Parcours de toutes les cases de la map
    for (y = 0; y < sizeY; y++) {
        for (x = 0; x < sizeX; x++) {

            // Récupération de la case à la position courante
            currentCase = levelGetCaseAt(aLevel, x, y);

            // Affichage de la case courante.
            draw3DCase(aLevel, currentCase, -x, y);
        }
    }
}

void draw3DPacBalls(PacLevel* aLevel) {
    pac_log(LOG_DEBUG, "draw3DPacBalls\n");

    int x, y = 0;

    // Récupération de la taille de la map
    int sizeY = levelGetSizeY(aLevel);
    int sizeX = levelGetSizeX(aLevel);

    int pacBallCode;

    // Parcours de toutes les cases de la map
    for (y = 0; y < sizeY; y++) {
        for (x = 0; x < sizeX; x++) {

            // Récupération de la PacGum à la position voulue
            pacBallCode = levelGetPacBallAt(aLevel, x, y);

            // Affichage de la case courante.
            draw3DPacBall(aLevel, pacBallCode, -x, y);
        }
    }
}

void draw3DMap(PacGame * aPacGame) {
    pac_log(LOG_DEBUG, "draw3DMap\n");

    // Désactivation des textures
    glBindTexture(GL_TEXTURE_2D, 0);

    // Affichage de PacMan
    draw3DPacMan(aPacGame, aPacGame->currentLevel->pacMan);

    // Affichage des Fantomes
    draw3DGhosts(aPacGame);

    // Affiches les PacBalls (PacGums et PowerBalls)
    draw3DPacBalls(aPacGame->currentLevel);

    // Affichage de la map
    draw3DCases(aPacGame->currentLevel);
    
    // Affichage de la skyBox
    drawSkyBox();

}